package pimp.organizermanager;

import java.util.*;

public class CyclicCalendar extends OurCalendar{

    private List<Cycle> cycles;

    private static class Singleton {
        private final static CyclicCalendar instance = new CyclicCalendar();
    }

    private CyclicCalendar() {
        cycles = new ArrayList<Cycle>();
        System.out.println("CyclicCalendar initialization completed!");
    }
 
    public static CyclicCalendar getInstance() {
        return Singleton.instance;
    }

    public boolean addCycle(Cycle cycle) {
        cycles.add(cycle);
        return true;
    }

    Map<GlobalEvent, Vector<Date>> getOccuranceOfCycles (Date beginDate, Date endDate) {
        Map<GlobalEvent, Vector<Date>> map = new HashMap<GlobalEvent, Vector<Date>>();

        for(int i = 0; i < cycles.size(); ++i) {
            Cycle cycle = cycles.get(i);
            Vector<Date> dates = this.findDates(beginDate, endDate, cycle, false);
            if(dates.size() > 0) {
                GlobalEvent globalEvent = cycle.getGlobalEvent();
                map.put(globalEvent, dates);
            }
        }

        return map;
    }

    private boolean doesOccure(Date beginDate, Date endDate, Cycle cycle) {
        Vector<Date> check = this.findDates(beginDate, endDate, cycle, true);

        if(check.size() > 0) {
            return true;
        }
        else {
            return false;
        }
    }

    private Vector<Date> findDates(Date beginDate, Date endDate, Cycle cycle,
            boolean firstOccurance) {
        Vector<Date> result = new Vector<Date> ();
        Vector<Date> cycleDates = cycle.getBeginDates();
        Date cycleFinish = cycle.getFinishDate();
        Rule rule = cycle.getRule();

        int xDays = rule.getDays();
        int xMonths = rule.getMonths();
        int xYears = rule.getYears();

        Vector<Date> exceptions = rule.getExceptions();

       Vector<Date> lastOccurance = new Vector<Date> ();
       Date lastDate;

       int size = cycleDates.size();

       for(int i = 0; i < size ; ++i) {
           Date date = cycleDates.get(i);
           if(Date.compareDates(date, endDate)) {
               lastOccurance.add(date);
               lastDate = date;
           }
           else {
               break;
           }
       }
       if(lastOccurance.size() == 0) {
           return result;
       }
       lastDate = lastOccurance.get(0);

       size = lastOccurance.size();

       while(Date.compareDates(lastDate, endDate) && Date.compareDates(lastDate,
               cycleFinish) ) {
           lastDate = lastOccurance.get(0);
           for(int i = 0; i < size; ++i) {
               Date date = lastOccurance.get(i);
               if(Date.compareDates(beginDate, date) && Date.compareDates(date, endDate)) {
                   result.add(date);
                   if(firstOccurance) {
                       for(int j = 0; j < exceptions.size(); ++j) {
                           if(Date.compareDates(date, exceptions.get(j))) {
                               result.remove(0);
                               break;
                           }
                       }
                       if(result.size() > 0) {
                           return result;
                       }
                   }
               }
               int thatYear = date.getThisYear();
               int thatMonth = date.getThisMonth();
               int thatDay = date.getThisDay();

               thatYear += xYears;
               thatMonth += xMonths;
               if(thatMonth > 12) {
                   thatYear += 1;
                   thatMonth = thatMonth % 12;
               }
               thatDay += xDays;
               int monthDays = CyclicCalendar.calculateDaysInMonth(thatYear, thatMonth);
               if(thatDay > monthDays) {
                   thatMonth = thatMonth + 1;
                   if(thatMonth > 12) {
                       thatYear += 1;
                       thatMonth = thatMonth % 12;
                   }
                   thatDay = thatDay % monthDays;
               }

               System.out.println("This is what I calculated: " + thatYear +"-"+
                       thatMonth+"-"+thatDay);
               Date tmpDate = new Date(thatYear, thatMonth, thatDay);
               tmpDate.printDate();
               lastOccurance.set(i, tmpDate);
           }
       }
       
       size = result.size();
       for(int i = 0; i < size; ++i) {
           for(int j = 0; j < exceptions.size(); ++j) {
               if(Date.isEqual(result.get(i), exceptions.get(j))) {
                   result.remove(i);
                   --i;
                   size -= 1;
                   break;
               }
           }
       }

        return result;
    }
    
    public Map<ID, GlobalEvent> getGlobalEventByDate(Date beginDate, Date endDate) {
        Map<ID, GlobalEvent> map = new HashMap<ID, GlobalEvent>();
        
        for(int i = 0; i < cycles.size(); ++i) {
            Cycle cycle = cycles.get(i);
            if(this.doesOccure(beginDate, endDate, cycle)) {
                GlobalEvent globalEvent = cycle.getGlobalEvent();
                map.put(globalEvent.getId(), globalEvent);
            }
        }
        
        return map;
    }

    @Override
    public Map <ID, GlobalEvent> getGlobalEventByDate(Date beginDate, Date endDate,
            ID id) {
        throw new UnsupportedOperationException("Not supported yet.");
    }
}
